
#include "stdafx.h"

#define TEXT_LENGTH  600
#define NUM_LENGTH    50
#define MAX_CONCAT     5
#define MAX_OBJECT     5

#define EMS_NULL     0
#define EMS_SOUND    1
#define EMS_ANIM     2
#define EMS_INVALID  9

struct object {
	int type;
	int value;
	int position;
};
struct object attach[MAX_OBJECT];

char smsc[NUM_LENGTH+1]="";
char number[NUM_LENGTH+1]="";
char text[TEXT_LENGTH+1]="";
char file_text[TEXT_LENGTH+1]="";
char val[10]="";
char port[10]="";
int classe=-1;
int type=-1;
int repeat=1;
int com_port=1;
int baud=9600;
int validity=-1;
int delay=0;
int port_from=-1;
int port_to=-1;

bool modem_check_flag=false;
bool alert_sms_flag=false;
bool ems_flag=false;
bool report_notification_flag=false;
bool pdu_mode_flag=false;
bool eight_bit_flag=false;
int pdu_mode_activation=-1;

char *version="0.51 - 2004-05-17";

char PDU[700]="";


void usage() {
	printf("Usage: sms -d number [-z] [-v validity] [-c class] [-s smsc] [-x COMn]\n");
	printf("           [-b baudrate] [-P mode] [-t type] [-h] [-w] [-p] [-n count]\n");
	printf("           [-D delay] [-e] [-f file] testo/pdu\n\n");
	printf("Options:\n");
	printf("   -z    Test modem connection. Can be used with -x and -b flags.\n");
	printf("   -d    Destination number in national or international format.\n");
	printf("   -v    Validity of SMS. Default: not set.\n");
	printf("         From 5m to 720m: minutes in step by 5 minutes\n");
	printf("         From 1h to 24h: hours\n");
	printf("         From 1d to 21d: days\n");
	printf("   -r    Report notification enabled.\n");
	printf("   -8    8 bit coding. Default: 7 bit coding\n");
	printf("   -c    Class of SMS. 0=flash, 1=standard, 2=SIM, 3=TE. Default=1\n");
	printf("   -s    SMSC number in international format.\n");
	printf("   -x    COM port. Supports only from COM1 to COM9. Default=COM1\n");
	printf("   -b    Baud rate. Supports 1200, 2400, 4800, 9600, 19200, 38400, 76800.\n");
	printf("         Default=9600\n");
	printf("   -t    Type. 0=Discarded, 1-7=Replace type. Default: no type\n");
	printf("   -a    Alert SMS. Max 69 chars. Not with -c, -t, -p, -e, -8, -o.\n");
	printf("   -h    Help. Shows this help!\n");
	printf("   -w    Version. Shows version of this program!\n");
	printf("   -p    PDU mode. Accept directly the PDU. Overrides all other flags.\n");
	printf("   -n    Number of times to send the SMS. Default=1\n");
	printf("   -f    Load text to send from a file. It overrides text (if present).\n");
	printf("   -D    Delay in seconds between each message (-n flag present).\n");
	printf("   -P    Activation of PDU mode: -1=always, 0=never, 1=1 time. Def: -1.\n");
	printf("   -e    EMS format for text messages. \\aX for anims, \\sX for sounds.\n");
	printf("   -o    16bit port scheme: src:dest in hex format (ex: 0000:80FF).\n");
	printf("\n");
}


void ems_parser(char *text, struct object *y) {
	char tmp[TEXT_LENGTH+1];
	unsigned int i=0,j=0;
	int cont=0;
	memset(tmp,0,TEXT_LENGTH+1);

	// Reset of attached structs
	for (int k=0; k<MAX_OBJECT; k++)
		y[j].type=EMS_NULL;
	
	while (i<strlen(text)) {
		if (i<strlen(text)-2) {
			if (text[i]=='\\' && (text[i+1]=='a' || text[i+1]=='s') && text[i+2]>='0' && text[i+2]<='9' && cont<MAX_OBJECT) {
				if (text[i+1]=='a')
					y[cont].type=EMS_ANIM;
				else
					y[cont].type=EMS_SOUND;
				y[cont].value=text[i+2]-'0';
				y[cont].position=j;
				i+=3;
				if ( (y[cont].type==EMS_ANIM && y[cont].value>14) || (y[cont].type==EMS_SOUND && y[cont].value>9) )
					y[cont].type=EMS_INVALID;
				cont++;
				continue;
			}
		}
		tmp[j++]=text[i++];
	}
	strcpy(text,tmp);
}

bool load_file(char *filename, char *text) {
	FILE *fp;
	fp=fopen(filename,"r");
	if (fp==NULL) {
		printf("Error opening the file: %s\n",filename);
		return false;
	}
	if (fread (text, 1, TEXT_LENGTH, fp)<=0) {
		printf("Error reading the file: %s\n",filename);
		return false;
	}
	return true;
}

bool check_direct_pdu(char *x) {
	if (strlen(x)<18 || strlen(x)%2==1)
		return false;
	for (unsigned int i=0; i<strlen(x); i++)
		if ( (x[i]<'0' || x[i]>'9') && (x[i]<'A' || x[i]>'F') )
			return false;
	return true;
}

bool check_number(char *x) {
	if (strlen(x)<3)
		return false;
	if ( (x[0]!='+') && (x[0]<'0' || x[0]>'9') )
		return false;
	for (unsigned int i=1; i<strlen(x); i++)
		if (x[i]<'0' || x[i]>'9')
			return false;
	return true;
}

int check_validity(char *x) {
	if (strlen(x)==0)
		return -1;
	int val=atoi(x);
	switch (x[strlen(x)-1]) {
	case 'm':
		if (val<5 || val>720 || val%5!=0)
			return -2;
		return val/5-1;
	case 'h':
		if (val<1 || val>24)
			return -2;
		if (val<=12)
			return val*12-1;
		else
			return (val-13)*2+145;
	case 'd':
		if (val<1 || val>22)
			return -2;
		return 167+val-1;
	default:
		return -2;
	}
	return -2;
}

bool check_port(char *x, int* from, int* to) {
	if (strlen(x)==0)
		return true;
	sscanf(x,"%x:%x",from,to);
	if (*from==-1 || *to==-1)
		return false;
	return true;
}

// Convert text according to 7 bit specs. Returns length of new string (it may contain 0x00)
int SevenBitCoding(char *x) {
	int l=strlen(x);
	char tmp[TEXT_LENGTH+1];
	strcpy(tmp,x);
	
	int j=0;
	for (unsigned int i=0; i<strlen(tmp); i++) {
		switch (tmp[i]) {
	   	case 64:
			x[j++]=0; break;
		case 163:
			x[j++]=1; break;
		case 36:
			x[j++]=2; break;
		case 165:
			x[j++]=3; break;
	    case 232:
			x[j++]=4; break;
		case 233:
			x[j++]=5; break;
		case 249:
			x[j++]=6; break;
		case 236:
			x[j++]=7; break;
		case 242:
			x[j++]=8; break;
		case 199:
			x[j++]=9; break;
		case 216:
			x[j++]=11; break;
		case 248:
			x[j++]=12; break;
		case 197:
			x[j++]=14; break;
		case 229:
			x[j++]=15; break;
		case 42:
			x[j++]=16; break;
		case 95:
			x[j++]=17; break;
		case 198:
			x[j++]=28; break;
		case 230:
			x[j++]=29; break;
		case 223:
			x[j++]=30; break;
		case 201:
			x[j++]=31; break;
		case 161:
			x[j++]=64; break;
		case 196:
			x[j++]=91; break;
		case 214:
			x[j++]=92; break;
		case 209:
			x[j++]=93; break;
		case 220:
			x[j++]=94; break;
		case 167:
			x[j++]=95; break;
		case 191:
			x[j++]=96; break;
		case 228:
			x[j++]=123; break;
		case 246:
			x[j++]=124; break;
		case 241:
			x[j++]=125; break;
		case 252:
			x[j++]=126; break;
		case 224:
			x[j++]=127; break;
		case 94:
			x[j++]=27; x[j++]=20; l++; break;
		case 123:
			x[j++]=27; x[j++]=40; l++; break;
		case 125:
			x[j++]=27; x[j++]=41; l++; break;
		case 92:
			x[j++]=27; x[j++]=47; l++; break;
		case 91:
			x[j++]=27; x[j++]=60; l++; break;
		case 126:
			x[j++]=27; x[j++]=61; l++; break;
		case 93:
			x[j++]=27; x[j++]=62; l++; break;
		case 124:
			x[j++]=27; x[j++]=64; l++; break;
		case 164:
			x[j++]=27; x[j++]=101; l++; break;
		default:
			if (tmp[i]>127)
				x[j++]='*';	// Default character for non standard input
			else
				x[j++]=tmp[i];
			break;
		}
	}
	return l;
}

// Convert the number to the format needed in the PDU
void calc_pdu_number(char *x, char *y) {
	char *start=x;	// national format
	if (x[0]=='+')	// international format with '+'
		start=x+1;
	if (x[0]=='0' && x[1]=='0')		// international format with '00'
		start=x+2;
	strcpy(y,start);
	if (strlen(y)%2==1)
		strcat(y,"F");

    for (unsigned int i=0; i<strlen(y); i+=2) {
		char swap=y[i];
		y[i]=y[i+1];
		y[i+1]=swap;
	}
}

void calc_pdu_number_format(char *n, char *y) {
	if ( (n[0]=='+') || (n[0]=='0' && n[1]=='0') )
		strcpy(y,"91");
	else
		strcpy(y,"81");
}

void calc_pdu_number_len(char *x, char *y){
	int l=strlen(x);
	sprintf(y,"%02X",l);
}

void calc_pdu_smsc(char *smsc, char *y) {
	char format[3];
	int length;
	char tmp_smsc[NUM_LENGTH+1];

	if (strlen(smsc)==0) {
		strcpy(y,"00");
		return;
	}
	// check international format
	if (smsc[0]!='+' && (smsc[0]!='0' && smsc[1]!='0') ) {
		strcpy(y,"00");
		return;
	}
	calc_pdu_number(smsc,tmp_smsc);
	calc_pdu_number_format(smsc,format);
	length=(strlen(format)+strlen(tmp_smsc))/2;
	sprintf(y,"%02X%s%s",length,format,tmp_smsc);
}

void calc_pdu_dcs(int classe, bool eight_bit_flag, char *y) {
	if (classe==-1)
		strcpy(y,"00");
	else
		sprintf(y,"1%d",classe);
	if (eight_bit_flag)
		y[1]=y[1]+4;

}

void calc_pdu_pid(int type, char *y) {
	if (type==-1)
		strcpy(y,"00");
	else
		sprintf(y,"4%d",type);
}

void calc_pdu_layout(bool ems, bool report_notification_flag, int validity, char *y){
	int l1=0, l2=1;	// nibbles of layout
	if (report_notification_flag)
		l1+=2;
	if (ems)
		l1+=4;
	if (validity != -1)
		l1+=1;
	sprintf(y,"%1d%1d",l1,l2);
}

void calc_pdu_validity(int x, char *y) {
	if (x == -1)
		strcpy(y,"");
	else
		sprintf(y,"%02X",x);
}

void calc_pdu_text_len(int sept_text, char *udh, char *y) {
	int sept_udh=0;
	if (strlen(udh)>0) {
		double tmp=0.0;
		tmp=strlen(udh)/2*8.0/7.0;			// Number of septets in udh
		if (tmp!=floor(tmp))
			tmp=tmp+1.0;
		sept_udh=(int)floor(tmp);
	}
	sprintf(y,"%02X",sept_udh+sept_text);
}

void calc_udh(char *x) {		// Adds the length of udh at the beginning
	char tmp[TEXT_LENGTH+1];
	if (strlen(x)==0)
		return;
	sprintf(tmp,"%02X",strlen(x)/2);
	strcat(tmp,x);
	strcpy(x,tmp);
}

void calc_pdu_text_7(int udh_len, char *x, unsigned int length, char *y) {
	unsigned int i;
    char dummy[170]="";
    unsigned int padding_len = 0;
	unsigned char tmp[TEXT_LENGTH+1];

	// New dummy string with initial padding for EMS
	memset(dummy,0,170);
	if (udh_len%7 != 0) {
		memset(dummy,1,udh_len%7+1);
		padding_len = strlen(dummy);
	}
	memcpy(&dummy[padding_len],x,length);
	length = length + padding_len;

	// 7 bit coding!
	for (i=0; i<length; i++) 
		tmp[i-i/8]=( (char)  dummy[i]>>i%8) | (char)(dummy[i+1]<<(8-1-i%8) );

	// Final string for output
	strcpy(y,"");
	for (i=padding_len-(padding_len==0?0:1); i<length-length/8; i++) {
		char t[2];
		sprintf(t,"%02X",tmp[i]);
		strcat(y,t);
	}
}

void calc_pdu_text_8(char *x, char *y) {
	strcpy(y,"");
	for (unsigned int i=0; i<strlen(x); i++) {
		char t[2];
		sprintf(t,"%02X",x[i]);
		strcat(y,t);
	}
}

bool Data2Pdu(char *PDU, char *numero, char *smsc, int classe, int validity, int type,
			  bool report_notification_flag, bool eight_bit_flag, char *udh, int length, char *text) {
	char pdu_layout[3];
	char pdu_number[NUM_LENGTH+1];
	char pdu_smsc[NUM_LENGTH+1];
	char pdu_number_len[3];
	char pdu_number_format[3];
	char pdu_dcs[3];
	char pdu_pid[3];
	char pdu_text[TEXT_LENGTH+1];
	char pdu_text_len[3];
	char pdu_validity[3];
	bool ems=(strlen(udh)>0);

	calc_udh(udh);
	calc_pdu_layout(ems, report_notification_flag, validity, pdu_layout);
	calc_pdu_number(number, pdu_number);
	calc_pdu_smsc(smsc, pdu_smsc);
	calc_pdu_number_format(number,pdu_number_format);
	calc_pdu_number_len(pdu_number,pdu_number_len);
	calc_pdu_dcs(classe,eight_bit_flag,pdu_dcs);
    calc_pdu_pid(type,pdu_pid);
	if (eight_bit_flag==false) {		// 7 bit encoding
		calc_pdu_text_7(strlen(udh)/2, text,length,pdu_text);
		calc_pdu_text_len(length,udh,pdu_text_len);
	}
	else {								// 8 bit encoding
		calc_pdu_text_8(text,pdu_text);
		sprintf(pdu_text_len,"%02X",length+strlen(udh)/2);
	}
	calc_pdu_validity(validity,pdu_validity);

	strcpy(PDU,"");
	strcat(PDU,pdu_smsc);			// Standard beginning
	strcat(PDU,pdu_layout);			// SMS layout
	strcat(PDU,"00");				// TP-MR message reference. 00=phone decides it.
	strcat(PDU,pdu_number_len);		// Lenght of the number of destination
	strcat(PDU,pdu_number_format);	// Number format (international or national)
	strcat(PDU,pdu_number);			// Number of destination
	strcat(PDU,pdu_pid);			// PID
	strcat(PDU,pdu_dcs);			// DCS
	strcat(PDU,pdu_validity);		// Validity
	strcat(PDU,pdu_text_len);		// Lenght in septets of the text of the SMS
	strcat(PDU,udh);				// UDH (for EMS and concatenated SMS)
	strcat(PDU,pdu_text);			// Text of SMS

	return true;
}

bool crea_alert_pdu(char *PDU, char *text, char *number, char *smsc, int validity) {
	char pdu_number[NUM_LENGTH+1];
	char pdu_number_len[3];
	char pdu_layout[3];
	char pdu_text[TEXT_LENGTH+1];
	char pdu_text_len[3];
	char pdu_validity[3];

	calc_pdu_number(number, pdu_number);
	calc_pdu_number_len(pdu_number,pdu_number_len);
	calc_pdu_validity(validity,pdu_validity);
	calc_pdu_layout(false,false,validity,pdu_layout);

	// Create pdu text, adding char 0001 to head of text
	strcpy(pdu_text,"0001");
	char cursor[5];
	for (unsigned int i=0; i<strlen(text); i++) {
		sprintf(cursor,"00%02X",text[i]);
		strcat(pdu_text,cursor);
	}
	sprintf(pdu_text_len,"%02X",strlen(pdu_text)/2);

	strcpy(PDU,"");
	strcat(PDU,"00");				// Standard beginning
	strcat(PDU,pdu_layout);			// layout (Standard SMS)
	strcat(PDU,"00");				// TP-MR message reference. 00=phone decides it.
	strcat(PDU,pdu_number_len);		// Lenght of the number of destination
	strcat(PDU,"91");				// International format
	strcat(PDU,pdu_number);			// Number of destination
	strcat(PDU,"00");				// PID (00)
	strcat(PDU,"18");				// DCS (18 -> 16 bits UCS2, message class 0)
	strcat(PDU,pdu_validity);		// Validity
	strcat(PDU,pdu_text_len);		// Lenght in septets/octets of the text of the SMS
	strcat(PDU,pdu_text);			// Text of SMS (in unicode)

	return true;	
}

// Waits "OK" or "ERROR" from phone: maximum time and steps to check serial port (in ms).
bool wait_ok(int max, int step, CSerial *serial) {
	int elapsed=0;
	char ReadBuffer[400];
	memset(ReadBuffer,0,400);
	char *ptr=ReadBuffer;

	while (elapsed<max) {
		Sleep(step);
		elapsed+=step;
		(*serial).ReadData(ptr, 500-(ptr-ReadBuffer));
		if (strstr(ReadBuffer,"OK")!=NULL)
			return true;
		if (strstr(ReadBuffer,"ERROR")!=NULL)
			return false;
	}
	return false;
}

bool check_modem(int com_port, int baud) {
	CSerial serial;
	char command[30];

	// Open COM port
	if (! serial.Open(com_port, baud))
		return false;
	// Send AT command for test
	sprintf(command,"AT\r");
	serial.SendData(command, strlen(command));

	return wait_ok(1000,200,&serial);
}


bool SendSms(char *pdu, int com_port, int baud, int *pdu_mode_activation) {
	CSerial serial;
	int nBytesSent;
	char command[500];

	// Open COM port
	if (serial.Open(com_port, baud))
		printf("Port opened successfully!\n");
	else {
		printf("Failed to open port!\n");
		return false;
	}

	// Command for PDU mode
	if (*pdu_mode_activation != 0) {
		sprintf(command,"AT+CMGF=0\r");
		nBytesSent = serial.SendData(command, strlen(command));

		if (!wait_ok(2000,200,&serial)) {
			printf("PDU mode failed.\n");
			return false;
		}
		printf("PDU mode activated.\n");
		*pdu_mode_activation = *pdu_mode_activation - 1;
	}

	// Command to send SMS
	sprintf(command,"AT+CMGS=%d\r",strlen(pdu)/2-1);
	nBytesSent = serial.SendData(command, strlen(command));
	Sleep(300);

	// Ctrl+Z at the end of PDU
	strcat(pdu," ");
	pdu[strlen(pdu)-1]=26;

	// Sending the data PDU
	nBytesSent = serial.SendData(pdu, strlen(pdu));

	if (!wait_ok(15000,200,&serial)) {
		printf("Error sending SMS.\n");
		return false;
	}
	printf("SMS sent successfully!\n");

	serial.Close();
	return true;
}

int main(int argc, char* argv[])
{

	printf("Welcome in SMS Wizard!\n\n");

	// Lettura parametri di linea di comando
	int i=1;
	while (i<argc) {
		// Acquisizione del flag
		char *flag=argv[i++];
		if (flag[0]!='-' || strlen(flag)!=2) {	// Text of SMS
			memset(text,0,TEXT_LENGTH+1);
			strncpy(text,flag,TEXT_LENGTH);
		}
		else {
			switch(flag[1]) {
			case 'n':	// Count value of SMS
				if (i<argc)
					repeat=atoi(argv[i++]);
				break;
			case 'D':	// Delay between each SMS
				if (i<argc)
					delay=atoi(argv[i++]);
				break;
			case 'f':	// Load text from file
				if (i<argc)
					if (!load_file(argv[i++],file_text))
						return -1;
				break;
			case 'c':	// Class of SMS
				if (i<argc)
					classe=atoi(argv[i++]);
				break;
			case 'd':	// Destination number (in international format)
				if (i<argc) {
					memset(number,0,NUM_LENGTH+1);
					strncpy(number,argv[i++],NUM_LENGTH);
				}
				break;
			case 's':	// SMSC (in international format)
				if (i<argc) {
					memset(smsc,0,NUM_LENGTH+1);
					strncpy(smsc,argv[i++],NUM_LENGTH);
				}
				break;
			case 'v':	// Validity
				if (i<argc) {
					memset(val,0,10);
					strncpy(val,argv[i++],9);
				}
				break;
			case 'o':	// Port scheme
				if (i<argc) {
					memset(port,0,10);
					strncpy(port,argv[i++],9);
				}
				break;
			case '8':	// 8 bit encoding
				eight_bit_flag=true;
				break;
			case 'w':	// Version
				printf ("sms version: %s\n",version);
				break;
			case 't':	// Type
				if (i<argc)
					type=atoi(argv[i++]);
				break;
			case 'h':	// Help
				usage();
				break;
			case 'z':
				modem_check_flag=true;
				break;
			case 'p':
				pdu_mode_flag=true;
				break;
			case 'a':
				alert_sms_flag=true;
				break;
			case 'r':
				report_notification_flag=true;
				break;
			case 'e':
				ems_flag=true;
				break;
			case 'x':	// COM port
				if (i<argc) {
					char *c=argv[i++];
					if (strncmp(c,"COM",3)!=0)
						com_port=0;
					else
						com_port=atoi(&c[3]);
				}
				break;
			case 'b':	// Baud rate for COM port
				if (i<argc)
					baud=atoi(argv[i++]);
				break;
			case 'P':	// PDU mode activation
				if (i<argc)
					pdu_mode_activation=atoi(argv[i++]);
				break;
			default:
				printf("Parameter %s not valid!\n",flag);
				return -1;
				break;
			}
		}
	}

	// Input from file (if available)
	if (strlen(file_text)>0)
		strcpy(text,file_text);

	// Check modem (this must be done at end of parameters read... COM parameters)
	if (modem_check_flag) {
		if (! check_modem(com_port, baud)) {
			printf("Modem test: Failed!\n");
			return -1;
		}
		printf("Modem test: OK!\n");
	}

	// Number not present: exit program
	if (strlen(number)==0 && !pdu_mode_flag)
		return 0;

	// Check validity of arguments
	if (alert_sms_flag) {
		if (pdu_mode_flag || ems_flag || eight_bit_flag || classe!=-1 || type!=-1 || strlen(port)>0) {
			printf("Invalid arguments for Alert SMS.\n");
			return -1;
		}
		if (strlen(text)>69) {
			printf("Text message too long for alert SMS (max 69 characters).\n");
			return -1;
		}
	}
	if (!check_number(number) && !pdu_mode_flag) {
		printf("Invalid destination number!\n");
		return -1;
	}
	if (!check_number(smsc) && strlen(smsc)>0) {
		printf("Invalid SMSC number!\n");
		return -1;
	}
	if (delay<0 || delay>86400) {
		printf("Invalid delay value. Delay between 0 and 86400 (24h)\n");
		return -1;
	}
	if (classe<-1 || classe>3) {
		printf("Invalid class: class between 0 and 3.\n");
		return -1;
	}
	if (type<-1 || type>7) {
		printf("Invalid type: type between 0 and 7.\n");
		return -1;
	}
	if (com_port<1 || com_port>9) {
		printf("Invalid COM port. Port number between 1 and 9.\n");
		return -1;
	}
	if (baud!=1200 && baud!=2400 && baud!=4800 && baud!=9600 && baud!=19200 && baud!=38400 && baud!=76800) {
		printf("Invalid baud rate.\n");
		return -1;
	}
	if (pdu_mode_activation <-1 && pdu_mode_activation>1) {
		printf("Invalid parameter for activation of PDU mode.\n");
		return -1;
	}
	if ( (validity=check_validity(val)) == -2 ) {
		printf("Invalid validity value\n");
		return -1;
	}
	if (!check_port(port,&port_from,&port_to)) {
		printf("Invalid port values\n");
		return -1;
	}
	if (repeat<1 || repeat>200) {
		printf("Invalid value for count: count between 1 and 200.\n");
		return -1;
	}
	if (pdu_mode_flag) {
		if (check_direct_pdu(text))
			strcpy(PDU,text);
		else {
			printf("Invalid PDU string in PDU mode\n");
			return -1;
		}
	}

	// Text parser for EMS attachments
	if (ems_flag)
		ems_parser(text,attach);

	// Debug print on screen
	if (!pdu_mode_flag) {
		printf("Destination: %s\n",number);
		if (strlen(smsc)>0)
			printf("SMSC: %s\n",smsc);
		printf("Text: %s\n",text);
		if (classe!=-1)
			printf("Class: %d\n",classe);
		if (validity != -1)
			printf("Validity: %s (%d)\n",val,validity);
		if (type!=-1)
			printf("Type: %d\n",type);
		if (alert_sms_flag)
			printf("Alert SMS!\n");
		if (strlen(port)>0)
			printf("Ports: %04X -> %04X\n",port_from,port_to);
		for (int k=0; k<MAX_OBJECT; k++)
			if (attach[k].type!=EMS_NULL)
				printf("EMS obj #%d - type: %d - value: %d - pos: %d\n",k,attach[k].type,attach[k].value,attach[k].position);
		if (eight_bit_flag)
			printf("8 bit coding enabled.\n");
		printf("COM port: %d - Baud rate: %d\n",com_port, baud);
		if (repeat>1)
			printf("Count: %d - Delay: %d seconds\n",repeat,delay);
		printf("\n");
	}

	// Alert SMS
	if (alert_sms_flag) {
		crea_alert_pdu(PDU, text, number, smsc, validity);
		printf("PDU: %s\n");
	}
	
	// Sending Alert SMS and direct PDU mode
	if (alert_sms_flag || pdu_mode_flag) {
		int success=0;
		for (int iter=0; iter<repeat; iter++) {
			if (SendSms(PDU, com_port, baud, &pdu_mode_activation))
				success++;
			if (delay>0)
				Sleep(delay*1000);
		}
		printf("Result: sent successfully %d/%d messages (%d%%)!",success,repeat,(int)((100*success)/repeat));
		return 0;
	}

	// Handling of concatenated SMS (maximum MAX_CONCAT)
	srand( (unsigned int)time( (time_t *)NULL ) ); 
	int totali=1;
	int id=0;
	int length=0;
	int max_length=0;
	int single_max_length=0;
	int multiple_max_length=0;
	char array_text[MAX_CONCAT][TEXT_LENGTH];
	int array_length[MAX_CONCAT];
	char array_udh[MAX_CONCAT][TEXT_LENGTH];
	// Init
	for (int k=0; k<MAX_CONCAT; k++) {
		strcpy(array_text[k],"");
		strcpy(array_udh[k],"");
		array_length[k]=0;
	}

	// Handling of EMS
	if (ems_flag)
		for (int k=0; k<MAX_OBJECT; k++)
			if (attach[k].type!=EMS_NULL && attach[k].type!=EMS_INVALID) {
				char tmp_udh[10];
				sprintf(tmp_udh,"0X02%02X%02X",attach[k].position,attach[k].value);
				if (attach[k].type==EMS_ANIM)
					tmp_udh[1]='D';
				else if (attach[k].type==EMS_SOUND)
					tmp_udh[1]='B';
				strcat(array_udh[0],tmp_udh);
			}

	// Length values (text may contain 0x00 -> must use length parameter)
	if (eight_bit_flag) {			// 8 bit coding
		length=strlen(text);
		max_length=134*MAX_CONCAT;
		single_max_length=140;
		multiple_max_length=134;
	}
	else {							// 7 bit coding
		length=SevenBitCoding(text);
		max_length=153*MAX_CONCAT;
		single_max_length=160;
		multiple_max_length=153;
	}

	// Check of maximum supported length
	if (length>max_length) {
		printf("SMS length larger than maximum supported size (%d characters).\n",max_length);
		return -1;
	}

	if (length<=single_max_length) {	// Single SMS
		totali=1;
		strcpy(array_text[0],text);
		array_length[0]=length;
	}
	else {								// Concatenated SMS
		id=rand()%255; 
		totali=length/multiple_max_length+1;
		for (i=0; i<totali; i++) {
			array_length[i]=multiple_max_length;
			memcpy(array_text[i],text+multiple_max_length*i,multiple_max_length);
			sprintf(array_udh[i],"0003%02X%02X%02X",id,totali,i+1);
		}
		array_length[totali-1]=length%multiple_max_length;
	}

	// 16bit port scheme
	if (strlen(port)>0)
		for (i=0; i<totali; i++) {
			char tmp[13];
			sprintf(tmp,"0504%04X%04X",port_to,port_from);
			strcat(array_udh[i],tmp);
		}

	// Ready to send
	int success=0;
	for (int iter=0; iter<repeat; iter++) {
		bool sent_flag=true;
		for (i=0; i<totali; i++) {
			// Creation of PDU to send
			if (!Data2Pdu(PDU,number,smsc,classe,validity,type,report_notification_flag,eight_bit_flag,
				          array_udh[i],array_length[i],array_text[i])) {
				printf ("Error during the creation of the PDU.\n");
				return -1;
			}
			printf("PDU [%d/%d]: %s\n", i+1, totali, PDU);

			// Send SMS
			if (! SendSms(PDU, com_port, baud, &pdu_mode_activation) )
				sent_flag=false;
		}
		if (sent_flag)
			success++;
		if (delay>0)
			Sleep(delay*1000);
	}
	printf("Result: sent successfully %d/%d messages (%d%%)!",success,repeat,(int)((100*success)/repeat));

	return 0;
}

